import base64
import hashlib
import json
from urllib.parse import urlparse, parse_qs


def filter_type(_type: str):
    """
    过滤日志类型
    :param _type: 类型
    :return: 是否过滤
    """
    types = [
        'application/javascript', 'application/x-javascript', 'text/css', 'webp', 'image/png', 'image/gif',
        'image/jpeg', 'image/x-icon', 'application/octet-stream', 'text/javascript'
    ]
    if _type not in types:
        return True
    return False


def include_type(_type: str):
    """
    过滤出包含的日志类型
    :param _type: 类型
    :return: 是否过滤
    """
    types = ['application/json']
    return _type in types


def decompose_url(url):
    """
    将URL分解为其基本部分和参数。
    :param url: 要分解的url
    :return: 包含基本URL和参数字典的元组
    """
    parsedUrl = urlparse(url)
    baseUrl = parsedUrl.scheme + "://" + parsedUrl.netloc + parsedUrl.path
    params = parse_qs(parsedUrl.query)
    # 将参数字典中的列表转换为单个值
    params = {k: v[0] if len(v) == 1 else v for k, v in params.items()}
    return baseUrl, params


class BrowserResponse:
    def __init__(self, browser):
        self.browser = browser  # 浏览器
        self.requests = []  # 用来存储请求
        self.seen = set()  # 用来存储已经处理过的请求,防止重复
        self.requests_log = []  # 用来存储请求日志
        self.requestWill = []

        self.md5 = hashlib.md5()

    def clear(self):
        """
        清空请求
        """
        self.requests.clear()
        self.seen.clear()

    def refresh(self, deduplicate=True):
        """
        刷新请求
        :param deduplicate: 是否去重,默认去重
        """
        performance_log = self.browser.get_log('performance')  # 获取名称为 performance 的日志
        for packet in performance_log:
            message = json.loads(packet.get('message')).get('message')  # 获取message的数据
            # 如果method不是Network.responseReceived类型就不往下执行
            if message.get('method') != 'Network.responseReceived':
                continue
            packet_type = message.get('params').get('response').get('mimeType')  # 获取该请求返回的type
            if not include_type(_type=packet_type): continue  # 过滤type
            # if not filter_type(_type=packet_type): continue  # 过滤type
            # 获取请求的基本信息
            request_id = message.get('params').get('requestId')
            response = message.get('params').get('response')
            url = response.get('url')  # 请求的URL
            status = response.get('status')  # HTTP状态码
            mime_type = response.get('mimeType')  # 响应类型
            # 获取请求响应体，注意捕获异常
            try:
                response_body = self.browser.execute_cdp_cmd('Network.getResponseBody', {'requestId': request_id})
                if 'base64Encoded' in response_body and response_body['base64Encoded']:
                    body = base64.b64decode(response_body['body'])
                else:
                    body = response_body['body']
                body = json.loads(body)
            except Exception as e:
                body = f"Error getting response body: {e}"

            baseUrl, params = decompose_url(url)
            # 保存请求信息
            request_info = {
                'url': url,
                'params': params,
                'base_url': baseUrl,
                'status': status,
                'mime_type': mime_type,
                'response': body
            }
            if not deduplicate:
                self.requests.append(request_info)
            else:
                # 将url+body 用md5加密
                self.md5.update(f"{str(url)}{str(body)}".encode('utf-8'))
                identifier = self.md5.hexdigest()
                if identifier not in self.seen:
                    self.seen.add(identifier)
                    self.requests.append(request_info)

    def find_response(self, url_list: list, params={}):
        """
        查找请求
        :param url: 需要筛选的url列表(不用携带参数)
        :param params: 需要筛选的参数
        :return: 返回符合条件的请求
        """
        self.refresh()
        res = []
        normalized_url_list = [url.rstrip('/') for url in url_list]  # 去掉url末尾的斜杠
        for req in self.requests:
            normalized_req_url = req['base_url'].rstrip('/')  # 去掉url末尾的斜杠
            if normalized_req_url not in normalized_url_list: continue
            # 检查params中的所有键值对是否都存在于base_params中
            if not all(item in req['params'].items() for item in params.items()): continue
            res.append(req)

        return res
